﻿using System.Collections.Concurrent;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;

namespace Willow.Extensions
{
    /// <summary>
    /// 集合辅助类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public static class CollenctionsHelper<T>
    {
        private static readonly ConcurrentDictionary<string, LambdaExpression> Cache = new ConcurrentDictionary<string, LambdaExpression>();

        /// <summary>
        /// 排序
        /// </summary>
        /// <param name="source">The source.</param>
        /// <param name="propertyName">Name of the property.</param>
        /// <param name="sortDirection">The sort direction.</param>
        /// <returns></returns>
        internal static IOrderedQueryable<T> OrderBy(IQueryable<T> source, string propertyName, ListSortDirection sortDirection)
        {
            dynamic keySelector = GetLambdaExpression(propertyName);
            return sortDirection == ListSortDirection.Ascending
                ? Queryable.OrderBy(source, keySelector)
                : Queryable.OrderByDescending(source, keySelector);
        }

        /// <summary>
        /// 排序
        /// </summary>
        /// <param name="source">The source.</param>
        /// <param name="propertyName">Name of the property.</param>
        /// <param name="sortDirection">The sort direction.</param>
        /// <returns></returns>
        internal static IOrderedQueryable<T> ThenBy(IOrderedQueryable<T> source, string propertyName, ListSortDirection sortDirection)
        {
            dynamic keySelector = GetLambdaExpression(propertyName);
            return sortDirection == ListSortDirection.Ascending
                ? Queryable.ThenBy(source, keySelector)
                : Queryable.ThenByDescending(source, keySelector);
        }

        /// <summary>
        /// 获取排序的表达式
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        /// <returns></returns>
        private static LambdaExpression GetLambdaExpression(string propertyName)
        {
            if (Cache.ContainsKey(propertyName))
            {
                return Cache[propertyName];
            }
            ParameterExpression param = Expression.Parameter(typeof(T));
            //根据句号拆分，获取导航对象属性
            var propNames = propertyName.Split('.');
            Expression body = param;
            var typeOfProperty = typeof(T);
            foreach (var propName in propNames)
            {
                var property = typeOfProperty.GetProperty(propName);
                if (property == null) return null;
                body = Expression.Property(body, property);
                typeOfProperty = property.PropertyType;
            }
            LambdaExpression keySelector = Expression.Lambda(body, param);
            Cache[propertyName] = keySelector;
            return keySelector;
        }
    }

    public class PropertySortCondition
    {
        /// <summary>
        /// 构造一个指定属性名称的升序排序的排序条件
        /// </summary>
        /// <param name="propertyName">排序属性名称</param>
        public PropertySortCondition(string propertyName)
            : this(propertyName, ListSortDirection.Ascending) { }

        /// <summary>
        /// 构造一个排序属性名称和排序方式的排序条件
        /// </summary>
        /// <param name="propertyName">排序属性名称</param>
        /// <param name="sortDirection">排序方式(Asc:正序,Desc:倒序)</param>
        public PropertySortCondition(string propertyName, string sortDirection)
        {
            PropertyName = propertyName;
            ListSortDirection = sortDirection.ToLower() == "desc" ? ListSortDirection.Descending : ListSortDirection.Ascending;
        }

        /// <summary>
        /// 构造一个排序属性名称和排序方式的排序条件
        /// </summary>
        /// <param name="propertyName">排序属性名称</param>
        /// <param name="listSortDirection">排序方式</param>
        public PropertySortCondition(string propertyName, ListSortDirection listSortDirection)
        {
            PropertyName = propertyName;
            ListSortDirection = listSortDirection;
        }

        /// <summary>
        /// 获取或设置 排序属性名称
        /// </summary>
        public string PropertyName { get; set; }

        /// <summary>
        /// 获取或设置 排序方向
        /// </summary>
        public ListSortDirection ListSortDirection { get; set; }
    }

}
